﻿using Nancy;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using WNWRAPCONSUMERLib;

namespace aaAttributeBrowser
{
    /// <summary>
    /// The AlarmManager retrieves alarms and serves the up as a webpage
    /// </summary>
    public class AlarmManager
    {
        private static AlarmManager _singleton = new AlarmManager();
        private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private bool _registered = false;
        private wwAlarmConsumerClass _consumer;

        public static AlarmManager Singleton
        {
            get
            {
                return _singleton;
            }
        }
       
        /// <summary>
        /// Handles file requests.  Serves up a file from the web folder if it exists or returns a 404.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public Response Handle(string request)
        {
            try
            {
                var webroot = (Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase) + @"\Web").Replace("file:\\", "");
                var filepath = string.Format(@"{0}\{1}", webroot, request);
                if (File.Exists(filepath))
                    return new Response()
                    {
                        Contents = x =>
                        {
                            BinaryWriter writer = new BinaryWriter(x);
                            writer.Write(File.ReadAllBytes(filepath));
                            writer.Flush();
                        }, 
                        ContentType = GetContentType(filepath)//we need to return the correct MIME type for some things to work properly
                    };
                return new Response()
                {
                    StatusCode = HttpStatusCode.NotFound
                };

            }
            catch (Exception ex)
            {
                _log.Error(ex.ToString());
                return new Response()
                {
                    StatusCode = HttpStatusCode.InternalServerError
                };
            }
        }

        private string GetContentType(string filepath)
        {
            //TODO: refactor this out somewhere else
            //TODO: either fill this out for common file types or find a library to do it
            var ext = Path.GetExtension(filepath);
            switch (ext)
            {
                case ".js":
                    return "application/javascript";
                case ".html":
                    return "text/html";
                case ".css":
                    return "text/css";
                case ".png":
                    return "image/png";
                default:
                    return "application/octet-stream";
            }
        }

        /// <summary>
        /// Registers the alarm consumer
        /// TODO: provide a way to customise the query
        /// </summary>
        private void RegisterAlarmConsumer()
        {
            try
            {
                _consumer = new wwAlarmConsumerClass();
                _consumer.InitializeConsumer("aaAttributeBrowser");
                _consumer.RegisterConsumer(0, "aaAttributeBrowserConsumer", "aaAttributeBrowser", "1.0.0");
                _consumer.SetXmlAlarmQuery("<QUERIES DISPLAY_MODE=\"Summary\"><QUERY><NODE>localhost</NODE><PROVIDER>Galaxy</PROVIDER><GROUP>Network</GROUP></QUERY></QUERIES>");
                _registered = true;
            }
            catch (Exception ex)
            {
                _log.Error(ex.ToString());
            }
        }

        private List<Alarm> QueryAlarms()
        {
            try
            {

                object currentXMLAlarms;
                var xDoc = new XmlDocument();
                List<Alarm> alarms = new List<Alarm>();

                if (!_registered) RegisterAlarmConsumer();
                if (!_registered) return null;

                _consumer.GetXmlCurrentAlarms(100, out currentXMLAlarms);
                xDoc.LoadXml(currentXMLAlarms.ToString());
                //_log.Debug(currentXMLAlarms.ToString());
                var node = xDoc.SelectNodes("/ALARM_RECORDS/ALARM");

                if (node != null)
                {
                    foreach (XmlNode leafnode in node)
                    {
                        if (leafnode["TYPE"].InnerText.ToLower() != "comm")
                        {
                            alarms.Add(new Alarm()
                            {
                                State = leafnode["STATE"].InnerText,
                                Type = leafnode["TYPE"].InnerText,
                                Group = leafnode["GROUP"].InnerText,
                                TagName = leafnode["TAGNAME"].InnerText,
                                Time = leafnode["DATE"].InnerText + " " + leafnode["TIME"].InnerText,
                                Value = leafnode["VALUE"].InnerText,
                                Guid = leafnode["GUID"].InnerText,
                                Priority = leafnode["PRIORITY"].InnerText,
                                Description = leafnode["ALARM_COMMENT"].InnerText,
                                Operator = leafnode["ACK_OPERATOR_NAME"]?.InnerText
                            });
                        }
                    }
                }
                return alarms;
            }
            catch (Exception ex)
            {
                _log.Error(ex.ToString());
                return null;
            }
        }

        /// <summary>
        /// Get the current alarms as a JSON object
        /// </summary>
        /// <returns></returns>
        public Response GetAlarmJSON()
        {
            var alarms = QueryAlarms();
            if (alarms == null)
                return HttpStatusCode.ServiceUnavailable;//for example if we can't initialse the alarms for whatever reason
            var result = JsonConvert.SerializeObject(alarms);
            return new Response()
            {
                Contents = x =>
                {
                    StreamWriter writer = new StreamWriter(x);
                    writer.Write(result);
                    writer.Flush();
                },
                ContentType = "text/plain"
            };
        }
    }
}
